/**
 * File: WriteScoutSummary.java
 * Created by: mhaimel
 * Created on: 5 Jun 2009
 * CVS:  $Id: WriteScoutSummary.java,v 1.1 2009/06/19 13:02:49 mhaimel Exp $
 */
package uk.ac.ebi.velvet.processor;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.Callable;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import uk.ac.ebi.curtain.utils.file.FileInfo;
import uk.ac.ebi.curtain.utils.io.impl.FileIO;
import uk.ac.ebi.velvet.VelvetUncheckedException;
import uk.ac.ebi.velvet.config.VelvetArgs;
import uk.ac.ebi.velvet.config.VelvetDataAccessService;
import uk.ac.ebi.velvet.model.ContigData;
import uk.ac.ebi.velvet.model.MapLocation;
import uk.ac.ebi.velvet.model.ReadData;
import uk.ac.ebi.velvet.model.Supercontig;
import uk.ac.ebi.velvet.processor.impl.WalkingGuide;
import uk.ac.ebi.velvet.util.io.WriteException;

/**
 * @author mhaimel
 *
 */
public class WriteScoutSummary implements Callable<Supercontig> {
	private Log log = LogFactory.getLog(this.getClass());
	private final VelvetDataAccessService data;
	private final Supercontig sc;
	private SortedSet<Long> ctgList = new TreeSet<Long>();
	private SortedSet<Long> readSet = new TreeSet<Long>();
	private SortedSet<Long> pairedReadSet = new TreeSet<Long>();
	
	public WriteScoutSummary(Supercontig sc,VelvetDataAccessService vData) {
		this.data = vData;
		this.sc = sc;
	}	

	@Override
	public Supercontig call() throws Exception {
		write();
		return getSuperContig();
	}
	
	public void write() {
		checkDirectory();
		splitData();
		printSummary(getSummaryOutputFile(), getContigSet(), getReadSet(), getPairedReadSet());
	}
	
	/*
	 * F file_id fileName isPaired
	 * P file_id file_pos N_entries 
	 * */
	private void splitData(){
		for(ContigData ctg : getGuide().getPath()){
			addContig(ctg);
			for(MapLocation loc : ctg.getMapLocations()){
				ReadData read = getData().getRead(loc.getRead());
				if(read.hasUnpairedRead()){
					addRead(read.getFilePosition());
				} else {
					addPairedRead(read.getFilePosition());
				}
			}
		}
	}
	
	private static final char TYPE_CONTIG = 'C';
	private static final char TYPE_READ = 'R';
	private void printSummary(File outFile, Collection<Long> ctgSet, Collection<Long> readSet, SortedSet<Long> pairedSet) {
		getLog().debug(msg("Print summary ..."));
		Map<FileInfo, Integer> file2Id = new HashMap<FileInfo, Integer>();

		PrintWriter out = null;
		try {
			out = new FileIO(outFile).getPrintWriter();
			for(Long pos : ctgSet){
				addSummary(file2Id, pos,TYPE_CONTIG, 1, out);
			}
			for(Long pos : readSet){
				addSummary(file2Id, pos,TYPE_READ, 1, out);
			}
			for(Long pos : pairedSet){
				addSummary(file2Id, pos,TYPE_READ, 2, out);
			}
		} catch (IOException e) {
			throw new WriteException("Problems writing to file " + outFile,e);
		} finally{
			IOUtils.closeQuietly(out);
		}
	}	
	
	private int fileIdCnt = 0;
	private void addSummary(Map<FileInfo, Integer> file2Id,long globalPosition,char type, Integer nEntries,PrintWriter out){
		FileInfo fileInfo = getData().getFileForPosition(globalPosition);
		Long localPos = getData().translate2LocalPosition(globalPosition);
		Integer fileId = file2Id.get(fileInfo);
		if(null == fileId){
			fileId = ++fileIdCnt;
			file2Id.put(fileInfo, fileId);
			out.println("F\t"+fileId.toString()+"\t"+fileInfo.getFile()+"\t"+fileInfo.getReadType()+"\t"+fileInfo.getFileType());
			Integer insCat = getVelvetArgs().getInsertLengthCategory(fileInfo);
			Integer insLen = getVelvetArgs().getInsertLength(fileInfo);
			if(null != insCat && null != insLen){
				out.println("I\t"+fileId.toString()+"\t"+insCat.toString()+"\t"+insLen);
			}
		}
		out.println(type+"\t"+fileId.toString()+"\t"+localPos.toString()+"\t"+nEntries.toString());
	}
	
	/**
	 * Make sure the directory exists
	 */
	private void checkDirectory() {
		getLog().debug("Check if Directory exists ...");
		if(!getBaseDir().exists()){
			if(!getBaseDir().mkdirs()){
				throw new VelvetUncheckedException(
						"Not able to create base directory " + getBaseDir());
			}
		}
	}

	private VelvetArgs getVelvetArgs() {
		return getData().getVelvetArgs();
	}
	public File getSummaryOutputFile() {
		return getSuperContig().getSummaryOutputFile();
	}
	private SortedSet<Long> getReadSet() {
		return readSet;
	}	
	private SortedSet<Long> getPairedReadSet() {
		return pairedReadSet;
	}	
	private void addRead(long filePos){
		getReadSet().add(filePos);
	}
	private void addPairedRead(Long filePos){
		getPairedReadSet().add(filePos);
	}
	private VelvetDataAccessService getData() {
		return data;
	}
	private SortedSet<Long> getContigSet() {
		return ctgList;
	}
	private void addContig(ContigData ctg){
		getContigSet().add(ctg.getFilePosition());
	}
	private WalkingGuide getGuide() {
		return getSuperContig().getGuide();
	}
	
	private File getBaseDir() {
		return getSuperContig().getBaseDir();
	}
	private int getId() {
		return getSuperContig().getSuperContigId();
	}
	public Supercontig getSuperContig() {
		return sc;
	}
	private String msg(String msg){
		return "[" + getId()+"] " + msg; 
	}
	private Log getLog() {
		return log;
	}
}
